const CRC = require('crc');
const ReadCoilsRequestBody = require('./request/read-coils.js');
const ReadDiscreteInputsRequestBody = require('./request/read-discrete-inputs.js');
const ReadHoldingRegistersRequestBody = require('./request/read-holding-registers.js');
const ReadInputRegistersRequestBody = require('./request/read-input-registers.js');
const WriteSingleCoilRequestBody = require('./request/write-single-coil.js');
const WriteSingleRegisterRequestBody = require('./request/write-single-register.js');
const WriteMultipleCoilsRequestBody = require('./request/write-multiple-coils.js');
const WriteMultipleRegistersRequestBody = require('./request/write-multiple-registers.js');



/*------------------------------------------------------------------------------------------------*/
/*----------------------------------MODBUS读取操作--------------------------------------------------*/
/*------------------------------------------------------------------------------------------------*/
/** Create a new Read Coils Request Body.读数字量输出
 * @param {Number} staNO station number
 * @param {Number} start Start Address.
 * @param {Number} count Quantity of coils to be read.
 * @throws {InvalidStartAddressException} When Start address is larger than 0xFFFF.
 * @throws {InvalidQuantityException} When count is larger than 0x7D0.
 */
function ReadCoils(staNO, start, count) {
    try {
        let body = new ReadCoilsRequestBody(start, count);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}
/** Create a new Read Discrete Inputs Request Body.读数字量输入
 * @param {Number} staNO station number
 * @param {Number} start Start Address.
 * @param {Number} count Quantity of coils to be read.
 * @throws {InvalidStartAddressException} When Start address is larger than 0xFFFF.
 * @throws {InvalidQuantityException} When count is larger than 0x7D0.
 */
function ReadDiscreteInputs(staNO, start, count) {
    try {
        let body = new ReadDiscreteInputsRequestBody(start, count);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}

/** Create a new Read Holding Registers Request Body.读模拟量输出
 * @param {Number} staNO station number
 * @param {Number} start Start Address.
 * @param {Numer} count Quantity of registers to be read.
 * @throws {InvalidStartAddressException} When start address is larger than 0xFFFF.
 * @throws {InvalidQuantityException} When count is larger than 0x7D0.
 */
function ReadHoldingRegisters(staNO, start, count) {
    try {
        let body = new ReadHoldingRegistersRequestBody(start, count);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}
/** Create a new Read Input Registers Request Body.读模拟量输入(04)
 * @param {Number} staNO station number
 * @param {Number} start Start Address.
 * @param {Number} count Quantity of coils to be read.
 * @throws {InvalidStartAddressException} When Start address is larger than 0xFFFF.
 * @throws {InvalidQuantityException} When count is larger than 0x7D0.
 */
function ReadInputRegisters(staNO, start, count) {
    try {
        let body = new ReadInputRegistersRequestBody(start, count);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}
/*------------------------------------------------------------------------------------------------*/
/*----------------------------------MODBUS写入操作--------------------------------------------------*/
/*------------------------------------------------------------------------------------------------*/

/** Execute WriteSingleRegister Request (Function Code 0x06)写数字量输出
 * @param {Number} address Address.
 * @param {Number} value Value.
 * @returns {Promise}
 * @example
 * client.writeSingleRegister(10, 1234).then(function (res) {
 *   console.log(res.response, res.request)
 * }).catch(function (err) {
 *   ...
 * })
 */
function WriteSingleCoil(staNO, address, value) {
    try {
        let body = new WriteSingleCoilRequestBody(address, value);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}


/** Create a new Write Single Register Request Body.
 * @param {Number} staNO station number
 * @param {Number} address Write address.
 * @param {Number} value Value to be written.
 * @throws {InvalidStartAddressException} When address is larger than 0xFFFF.
 */
function WriteSingleRegister(staNO, address, value) {
    try {
        let body = new WriteSingleRegisterRequestBody(address, value);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}
/** Create a new Write Multiple Coils Request Body.
 * @param {Number} staNO station number
 * @param {Number} address Write address.
 * @param {Array|Buffer} values Values to be written. Either a Array of Boolean values or a Buffer.
 * @param {Number} quantity In case of values being a Buffer, specify the number of coils that needs to be written.
 * @throws {InvalidStartAddressException} When address is larger than 0xFFFF.
 * @throws {InvalidArraySizeException}
 * @throws {InvalidBufferSizeException}
 */

function WriteMultipleCoils(staNO, start, values, quantity) {
    try {
        let body = new WriteMultipleCoilsRequestBody(start, values, quantity);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;

    } catch (e) {
        console.log(e);
        return null;
    }

}

/** Create a new Write Multiple Registers Request Body.
 * @param {Number} staNO station number
 * @param {Number} address Write address.
 * @param {Array|Buffer} values Values to be written. Either a Array of UInt16 values or a Buffer.
 * @param {Number} quantity In case of values being a Buffer, specify the number of coils that needs to be written.
 * @throws {InvalidStartAddressException} When address is larger than 0xFFFF.
 * @throws {InvalidArraySizeException}
 * @throws {InvalidBufferSizeException}
 */
function WriteMultipleRegisters(staNO, address, values) {
    try {
        let body = new WriteMultipleRegistersRequestBody(address, values);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}

function WriteSingleRegister(staNO, address, value) {
    try {
        let body = new WriteSingleRegisterRequestBody(address, value);
        let payload = body.createPayload();
        let _crc = CRC.crc16modbus(Buffer.concat([Buffer.from([staNO]), payload]));
        const crBu = Buffer.alloc(2);
        crBu.writeUInt16LE(_crc);
        const idBuf = Buffer.from([staNO]);
        const cmdPacket = Buffer.concat([idBuf, payload, crBu]);
        // console.log(cmdPacket.toString('hex').toUpperCase());
        return cmdPacket;
    } catch (e) {
        console.log(e);
        return null;
    }

}
module.exports = {
    ReadCoils,
    ReadDiscreteInputs,
    ReadHoldingRegisters,
    ReadInputRegisters,
    WriteSingleCoil,
    WriteMultipleCoils,
    WriteMultipleRegisters,
    WriteSingleRegister
}